package modelx

import (
	"database/sql"
	"errors"
	"strconv"
	"strings"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/volatiletech/null/v8"
	"github.com/volatiletech/sqlboiler/v4/boil"
)

// 创建 mysql 连接
// Open handle to database like normal
func NewMysqlConn(connStr string) (*sql.DB, error) { // #24.02.23#
	if len(connStr) == 0 {
		return nil, errors.New("Mysql dataSource is empty")
	}

	db, err := sql.Open("mysql", connStr)
	if err != nil {
		// err: could not open database connection
		return nil, err
	}

	boil.DebugMode = true

	// https://www.alexedwards.net/blog/configuring-sqldb
	db.SetMaxOpenConns(25)
	db.SetMaxIdleConns(25)
	db.SetConnMaxLifetime(5 * time.Minute)

	if err = db.Ping(); err != nil {
		// err: no real database connection
		return nil, err
	}

	return db, nil
}

type ListInfo struct {
	UpdatedAt time.Time `boil:"last_updated_at"`
}

func UniqueValues(args []string, size int) (vals []any) { //////
	if len(args) == 0 {
		return
	}

	argMap := make(map[string]int)
	for idx, arg := range args {
		arg = strings.TrimSpace(arg)
		if _, ok := argMap[arg]; !ok {
			if id, err := strconv.ParseInt(arg, 10, size); err == nil {
				vals = append(vals, id)
			}

			argMap[arg] = idx
		}
	}

	return
}

// 用 "," 切分ids 且去重
func UniqueInterfaces(idStr string, size int) (vals []any) { // ##25.01.04## size 为0 则不分析是不是数字直接使用
	idStr = strings.TrimSpace(idStr)
	if len(idStr) == 0 {
		return
	}

	args := strings.Split(idStr, ",")
	if len(args) == 0 {
		return
	}

	argMap := make(map[string]struct{})
	for _, arg := range args {
		arg = strings.TrimSpace(arg)
		if len(arg) == 0 {
			continue
		}

		if _, ok := argMap[arg]; !ok {
			if size > 0 {
				if val, err := strconv.ParseInt(arg, 10, size); err == nil {
					vals = append(vals, val)
				} else {
					continue
				}
			} else {
				vals = append(vals, arg)
			}

			argMap[arg] = struct{}{}
		}
	}

	return
}

// De-duplication
func DedupeIds(ids []int64) (deduped []int64, idMap map[int64][]int) { //////
	idMap = make(map[int64][]int)
	for idx, id := range ids {
		if _, ok := idMap[id]; !ok {
			deduped = append(deduped, id)
		}

		idMap[id] = append(idMap[id], idx)
	}

	return
}

func ParseLocalTime(localTime string) (time.Time, error) { // #24.08.19#
	return time.ParseInLocation("2006-01-02 15:04:05", localTime, time.Local)
}

func ParseLocalDate(localTime string) (time.Time, error) { // #24.08.19#
	return time.ParseInLocation("2006-01-02", localTime, time.Local)
}

func GetGmtTime(localTime time.Time) time.Time { // time.Parse()的默认时区是UTC，time.Format()的时区默认是本地
	utcTime := localTime.In(time.UTC)
	gmtStr := utcTime.Format("2006-01-02T15:04:05")
	layout := "2006-01-02 15:04:05"

	gmtTime, err := time.ParseInLocation(layout, strings.Replace(gmtStr, "T", " ", -1), time.Local)
	if err != nil {
		return localTime
	}

	return gmtTime
}

func FormatTime(t time.Time, f string) string { // #24.02.29#
	if t.IsZero() {
		return ""
	}

	if f == "" {
		return t.Format("2006-01-02 15:04:05")
	}

	return t.Format(f)
}

func FormatTimeUnix(t time.Time) int64 {
	if t.IsZero() {
		return 0
	}

	return t.Unix()
}

func FormatNullDotTime(ndt null.Time, f string) string { // #24.02.29#
	if !ndt.Valid {
		return ""
	}

	t := ndt.Time

	if f == "" {
		return t.Format("2006-01-02 15:04:05")
	}

	return t.Format(f)
}

func FormatNullDotTimeUnix(ndt null.Time) int64 {
	if !ndt.Valid {
		return 0
	}

	t := ndt.Time
	return t.Unix()
}

func FormatNullDotString(ndt null.String) string { // #24.02.29#
	if !ndt.Valid {
		return ""
	}

	t := ndt.String

	return t
}

func GetNullString(ndt string) null.String { // #24.02.29#
	return null.String{
		String: ndt,
		Valid:  true,
	}
}
